package com.aleyn.router.plug.visitor

import com.aleyn.router.plug.data.HandleModel
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.commons.InstructionAdapter


/**
 * @author: Aleyn
 * @date: 2023/7/20 15:06
 *
 * ASM MethodVisitor, 用于向 `LRouterGenerateImpl.initModuleRouter` 方法中注入字节码。
 *
 * 这个类的职责是调用每个模块生成的路由注册类 (`LRouter$$` 后缀的类) 的静态方法，
 * 以完成路由表的加载和路由元信息的初始化。这避免了在运行时使用反射，从而提高了性能。
 *
 * 它会遍历所有被 `@RouteModule` 注解标记的模块，并为每个模块生成的 `LRouter$$` 类，
 * 调用其 `registerRouter()` 和 `initDefinition()` 两个静态方法。
 *
 * 此 Adapter 会在 `LRouterGenerateImpl.initModuleRouter()` 方法中生成如下等效代码：
 * ```java
 * // 假设有一个模块 'app'，生成了 LRouter$$app 类
 * com.aleyn.router.LRouter$$app.registerRouter();
 * com.aleyn.router.LRouter$$app.initDefinition();
 * // ... 对其他模块重复此操作
 * ```
 *
 * @param api ASM API的版本。
 * @param methodVisitor 委托的下一个 MethodVisitor。
 * @param moduleClass 包含所有需要处理的模块注册类信息的列表。
 */
class ModuleRouterInstructAdapter(
    api: Int,
    methodVisitor: MethodVisitor,
    private val moduleClass: List<HandleModel.Module>?
) : InstructionAdapter(api, methodVisitor) {

    /**
     * 在目标方法的代码开始处被调用。
     *
     * 这是实现字节码注入的关键。
     * 它会遍历 `moduleClass` 列表，为每个模块的路由注册类生成静态方法调用指令。
     */
    override fun visitCode() {
        moduleClass?.forEach {
            // 调用静态方法 LRouter$$xx.registerRouter()
            // 这个方法负责将该模块的路由信息加载到全局路由表中
            invokestatic(
                it.className,
                "registerRouter",
                "()V",
                false
            )
            // 调用静态方法 LRouter$$xx.initDefinition()
            // 这个方法负责初始化该模块所有路由的元信息 (RouteMeta)
            invokestatic(
                it.className,
                "initDefinition",
                "()V",
                false
            )
        }
        super.visitCode()
    }

}